#pragma once

#include <string>
#include <stack>
#include <vector>

namespace CPreProc
{
  class Tokenizer;
  class Token;

  typedef std::string ExpressionError;
    
  inline std::string OperatorExpectedException()
  {
    return "Unexpected token. Operator expected.";
  }

  inline std::string OperandExpectedException()
  {
    return "Unexpected token. Operand expected.";
  }

  enum ExpOperator
  {
    Op_Mul,
    Op_Div,
    Op_Mod,

    Op_Add,
    Op_Sub,

    Op_Shr,
    Op_Shl,

    Op_Lt,
    Op_Gt,
    Op_Lte,
    Op_Gte,

    Op_Eq,
    Op_Neq,

    Op_BAnd,
    Op_BXor,
    Op_BOr,

    Op_LAnd,
    Op_LOr,

    Op_Neg,
    Op_Not,
    Op_Inv,

    // the following ops are only used during parsing, and will never 
    // occur in the final bytecode
    Op_Parenthesis,
    Op_Nop,

    // the following are only used as byte code, and not as an operator, 
    // in the operator stack
    Op_PushInt,
    Op_PushBigInt,
    Op_PushFloat,
  };

  class ExpressionValue
  {
  public:
    ExpressionValue(int int_value)
    {
      this->int_value = int_value;
      type = Type_Int;
    }

    union
    {
      guint32           int_value;
      float             float_value;
      Glib::ValueBase*  glib_value;
    };

    enum Type
    {
      Type_Int,
      Type_Float,
      Type_GlibValue,
    };
    Type type;
  };

  class Expression
  {
  public:
    void                  parse(const char *begin,const char *end);
    
    ExpressionValue       evaluate();

  private:
    std::vector<guint32>  byte_code;
  };
}

